/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.web.controller;

import com.google.common.collect.Lists;
import com.intelligent.ispc.common.dto.JsonPageResponseDto;
import com.intelligent.ispc.common.dto.JsonResponseDto;
import com.intelligent.ispc.common.mapper.JsonMapper;
import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import com.intelligent.ispc.common.web.ProcessEvent;
import com.intelligent.ispc.common.web.ProcessInfo;
import com.intelligent.ispc.common.web.Servlets;
import com.intelligent.ispc.core.dto.BaseDto;
import com.intelligent.ispc.core.dto.SpcDataImportParamDto;
import com.intelligent.ispc.core.dto.TestFileDto;
import com.intelligent.ispc.core.service.DataIOService;
import com.intelligent.ispc.core.service.SecurityService;
import com.intelligent.ispc.core.service.SpcAnalysisService;
import com.intelligent.ispc.core.service.TestFileService;
import com.intelligent.ispc.utils.Constant;
import com.intelligent.ispc.utils.SystemConfig;
import com.intelligent.ispc.web.utils.ApplicationUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 15/11/19.
 */
@Controller
@RequestMapping(value = "/data")
public class DataController {

    @Autowired
    private DataIOService dataIOService;

    @Autowired
    private SecurityService securityService;

    @Autowired
    private SimpMessagingTemplate msgTemplate;

    @Autowired
    private SystemConfig systemConfig;

    @Autowired
    private TestFileService testFileService;

    @Autowired
    private SpcAnalysisService spcAnalysisService;

    private long fileSize;
    private long readSize;

    @RequestMapping(value = "/import", method = RequestMethod.GET)
    public String dataImportIndex(Model model) {

        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("data:view")) {
            return "error/noPermission";
        }
        return "data/dataImport";
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public ModelAndView dataImport(HttpServletRequest request, HttpServletResponse response) {

        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("data:import")) {
            return new ModelAndView("error/noPermission");
        }

        ModelAndView mv = new ModelAndView();
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (!isMultipart) {
            return mv;
        }
        Map<Double, Double> mapProcess = new HashMap<Double, Double>();

        final HttpSession session = request.getSession();
        try {
            FileItemFactory factory = new DiskFileItemFactory();
            Long userId = securityService.getCurrentUser().getId();
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setProgressListener(new ProgressListener() {
                public void update(long pBytesRead, long pContentLength, int pItems) {
                    fileSize = pContentLength;
                }
            });
            List<FileItem> items = upload.parseRequest(request);
            StringBuffer buffer = new StringBuffer();

            String dirPath = buffer.append(File.separator)
                    .append(ApplicationUtil.getProjectPathSeparator())
                    .append("upload")
                    .append(File.separator).toString();

            List<BaseDto> filePaths = Lists.newArrayList();
            String projectId = "";
            String bu5Name = null;
            String bu5Enabled = null;
            String soltkey = null;
            for (FileItem item : items) {
                if (item.isFormField()) {
                    if (item.getFieldName().equalsIgnoreCase("projectId")) {
                        projectId = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bu5Name")) {
                        bu5Name = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bu5Enabled")) {
                        bu5Enabled = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("soltkey")) {
                        soltkey = item.getString();
                    }
                } else {

                    String fName = new Date().getTime() + "_" + item.getName();
                    String filePath = dirPath + fName;
                    BaseDto fileDto = new BaseDto();
                    fileDto.setKey(item.getName());
                    fileDto.setValue(filePath);
                    filePaths.add(fileDto);
                    File uploadFile = new File(filePath);
                    if (!uploadFile.exists()) {
                        uploadFile.createNewFile();
                    }
                    item.write(uploadFile);
                }
            }

            SpcDataImportParamDto spcDataImportParamDto = new SpcDataImportParamDto();
            spcDataImportParamDto.setFilePaths(filePaths);
            spcDataImportParamDto.setProjectId(projectId);
            spcDataImportParamDto.setFileSize(fileSize);
            if ("on".equalsIgnoreCase(bu5Enabled)) {
                spcDataImportParamDto.setBu5Flag(bu5Name);
            }

//            if (fileType.equals("csv")) {
            dataIOService.importDataFromCvs(spcDataImportParamDto, getProcessEvent(userId, Long.valueOf(soltkey)));
//            } else if (fileType.equals("xls") || fileType.equals("xlsx")) {
//                dataIOService.importDataFromExcel(dirPath + fileName, projectId, fileSize, getProcessEvent(userId));
//            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return mv;
    }


    @RequestMapping(value = "/history", method = RequestMethod.GET)
    public String history(Model model) {

        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("data:view")) {
            return "error/noPermission";
        }

        return "data/dataImportHistory";
    }

    @ResponseBody
    @RequestMapping(value = "/fileList")
    public JsonPageResponseDto list(Model model, ServletRequest request) {

        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("data:view")) {
            return JsonPageResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
        }

        Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

        Integer start = 0;
        if (StringUtils.isNotBlank(request.getParameter("start"))) {
            start = Integer.valueOf(request.getParameter("start"));
        }
        Integer size = systemConfig.getPageSize();
        if (StringUtils.isNotBlank(request.getParameter("length"))) {
            size = Integer.valueOf(request.getParameter("length"));
        }

        Integer draw = 0;
        if (StringUtils.isNotBlank(request.getParameter("draw"))) {
            draw = Integer.valueOf(request.getParameter("draw"));
        }

        Integer pageNum = 0;
        if ((start / size) > 0) {
            pageNum = start / size;
        }

        Sort sort = null;
        String sortField = request.getParameter("sortField");
        if (StringUtils.isNotBlank(sortField)) {
            sort = new Sort(Sort.Direction.DESC, sortField);
        }

        Page<TestFileDto> page = testFileService.searchTestFile(searchParam, new PageRequest(pageNum, size, sort));
        List<TestFileDto> dtos = page.getContent();

        JsonPageResponseDto json = JsonPageResponseDto.SUCCESS().setBody(dtos);
        json.setRecordsTotal(page.getTotalElements());
        json.setRecordsFiltered(page.getTotalElements());
        json.setDraw(draw);

        return json;
    }

    @ResponseBody
    @RequestMapping(value = "/checkTestFile")
    public JsonResponseDto checkTestFile(Model model, ServletRequest request) {

        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("data:import")) {
            return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
        }

        Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

        JsonMapper mapper = JsonMapper.nonDefaultMapper();
        List<String> originalNames = mapper.fromJson((String) searchParam.get("originalName"), mapper.contructCollectionType(List.class, String.class));
        boolean isHasFile = testFileService.checkTestFile(originalNames, (String) searchParam.get("projectId"));

        return JsonResponseDto.SUCCESS().setBody(isHasFile);
    }

    @ResponseBody
    @RequestMapping(value = "delete", method = RequestMethod.POST)
    public JsonResponseDto delete(@RequestParam("id") String id, @RequestParam("projectId") String projectId, Model models) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("data:destroy")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }
            testFileService.destroyTestFileAndTestItemName(id);
            spcAnalysisService.deleteTestData(id, projectId);
        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }
        return JsonResponseDto.SUCCESS();
    }

    @ResponseBody
    @RequestMapping(value = "logicDelete/{id}", method = RequestMethod.POST)
    public JsonResponseDto logicDelete(@PathVariable("id") String id, Model models) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("data:delete")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }
            testFileService.logicDeleteTestFile(id);
        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }
        return JsonResponseDto.SUCCESS();
    }

    @ResponseBody
    @RequestMapping(value = "restoreData/{id}", method = RequestMethod.POST)
    public JsonResponseDto restoreTestFile(@PathVariable("id") String id, Model models) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("data:restore")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }
            testFileService.restoreTestFile(id);
        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }
        return JsonResponseDto.SUCCESS();
    }

    private void sendListenerResponse(ProcessInfo response, Long userId, Long soltkey) {
        if (response == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        response.setTarget(Constant.UPLOAD_TARGET_SPC);
        JsonMapper mapper = new JsonMapper();
        String json = mapper.toJson(response);

        msgTemplate.setUserDestinationPrefix("/data/");
        msgTemplate.convertAndSend("/topic/data/importListener#" + soltkey + "#" + userId, json);
    }

    private void setFileSize(long size) {
        fileSize = size;
    }

    private void setReadSize(long size) {
        readSize = size;
    }

    private ProcessEvent getProcessEvent(Long userId, Long soltkey) {
        return new ProcessEvent() {
            @Override
            public void update(double rate, String log, long rowReadSize, boolean lastUpdate) {

                ProcessInfo pri = new ProcessInfo();
                pri.setRate(rate);
                pri.setLog(pri.getLog() + log);

                pri.setReadSize(rowReadSize);
                pri.setTotalSize(fileSize);
                pri.setLastUpdate(lastUpdate);
                sendListenerResponse(pri, userId, soltkey);
            }
        };

    }

}
